package com.bluefox.search.lucene;

import com.bluefox.search.lucene.convertor.LuceneConvert;
import com.bluefox.search.lucene.convertor.MapLuceneConvertor;
import lombok.extern.slf4j.Slf4j;
import org.apache.lucene.document.Document;
import org.apache.lucene.search.*;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
public class LuceneSearch {

    /**
     *  分页查询
     * @param page  LucenePage
     * @param query Query
     * @param convert LuceneConvert
     * @param <T> T
     * @return    LucenePage
     */
    public static <T> LucenePage<T> findPage(LucenePage<T> page, Query query, LuceneConvert<T> convert) {
        IndexSearcher indexSearcher = LuceneUtil.getIndexSearcher();
        int n = page.getFirstResult() + page.getPageSize();//查询前n条
        try {
            TopDocs topDocs = indexSearcher.search(query, n);
            long total = topDocs.totalHits; //实际总数
            page.setTotal(total);
            //会延迟加载
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;//指定前n条 实际得到的数量
            //分页
            int endIndex = Math.min(n, scoreDocs.length);
            List<T> list = new ArrayList<T>();
            for (int i = page.getFirstResult(); i < endIndex; i++) {
                Document doc = indexSearcher.doc(scoreDocs[i].doc);
                T t = convert.docToObject(doc);
                list.add(t);
            }
            page.setList(list);
            log.debug("一共匹配到：{},实际取：{}", total, scoreDocs.length);
        } catch (IOException e) {
            log.error("索引匹配失败");
            throw new RuntimeException(e);
        }
        return page;
    }

    /**
     * 查询所有
     *
     * @param query
     * @param convert
     * @return
     */
    public static <T> List<T> findAll(Query query, LuceneConvert<T> convert) {
        LucenePage<T> page = new LucenePage<T>(1, Integer.MAX_VALUE);
        return findPage(page, query, convert).getList();
    }

    public static <T> Page<T> getAll(Pageable pageable, Query query, LuceneConvert<T> convert) {
        Pageable page =   PageRequest.of(0,Integer.MAX_VALUE);
        return get(page, query, convert);
    }

    /**
     * 使用query 查询结果 将结果封装成Page对象返回
     * @param page
     * @param query
     * @param convert
     * @param <T>
     * @return
     */
    public static <T> Page<T> get(Pageable page, Query query, LuceneConvert<T> convert) {
        IndexSearcher indexSearcher = LuceneUtil.getIndexSearcher();
        int n = page.getPageNumber() * page.getPageSize() + page.getPageSize();
        try {
            //查询前n条
            TopDocs topDocs = indexSearcher.search(query, n);
            long total = topDocs.totalHits; //实际总数
            // page.setTotal(total);
            //会延迟加载
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;//指定前n条 实际得到的数量
            //分页 当前结束
            int endIndex = Math.min(n, scoreDocs.length);
            List<T> list = new ArrayList<T>();
            for (int i = page.getPageNumber() * page.getPageSize(); i < endIndex; i++) {

                Document doc = indexSearcher.doc(scoreDocs[i].doc);
                // 将文档转化为Object对象
                T t = convert.docToObject(doc);
                list.add(t);
            }
            // page.setList(list);
            Page<T> t = new PageImpl<T>(list, page, total);
            log.debug("一共匹配到：{},实际取：{}", total, scoreDocs.length);
            return t;
        } catch (Exception e) {
            log.error("索引匹配失败");
            throw new RuntimeException(e);
        }
    }

    public static Map print4SortTop1(Query query, Sort sort) {
        IndexSearcher indexSearcher = LuceneUtil.getIndexSearcher();
        try {
            TopDocs topDocs = indexSearcher.search(query, 1, sort);
            long total = topDocs.totalHits; //实际总数
            // page.setTotal(total);
            //会延迟加载
            ScoreDoc[] scoreDocs = topDocs.scoreDocs;//指定前n条 实际得到的数量
            if (scoreDocs.length == 0)
                return null;
            //分页
            int endIndex = Math.min(1, scoreDocs.length);
            List<Map> list = new ArrayList<Map>();
            MapLuceneConvertor convert = new MapLuceneConvertor();
            Document doc = indexSearcher.doc(scoreDocs[0].doc);
            Map t = convert.docToObject(doc);
            return t;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

}
